import { account, OAuthProvider } from '../config/appwrite';
import { 
  OAuthProvider as AppwriteOAuthProvider, 
  ID, 
  Models,
  AuthenticatorType,
  AuthenticationFactor
} from 'appwrite';

export class AuthService {
  // ========== Local Storage Keys ==========
  private readonly REGISTERED_EMAILS_KEY = 'kernelproxy_registered_emails';

  // ========== Helper Methods ==========
  
  /**
   * Mark email as registered in local storage (for backward compatibility)
   * @deprecated Only used for legacy OTP flow
   */
  private markEmailAsRegistered(email: string) {
    try {
      const registered = this.getRegisteredEmails();
      if (!registered.includes(email.toLowerCase())) {
        registered.push(email.toLowerCase());
        localStorage.setItem(this.REGISTERED_EMAILS_KEY, JSON.stringify(registered));
      }
    } catch (error) {
      console.error('Failed to mark email as registered:', error);
    }
  }

  /**
   * Get list of registered emails from local storage
   * @deprecated Only used for legacy OTP flow
   */
  private getRegisteredEmails(): string[] {
    try {
      const stored = localStorage.getItem(this.REGISTERED_EMAILS_KEY);
      return stored ? JSON.parse(stored) : [];
    } catch (error) {
      console.error('Failed to get registered emails:', error);
      return [];
    }
  }

  /**
   * Check if email is registered (for legacy OTP flow)
   * @deprecated Only used for legacy OTP flow
   */
  async checkUserExists(email: string): Promise<{ exists: boolean; isNewUser?: boolean; error?: any }> {
    try {
      // Check if currently logged in with this email
      try {
        const currentUser = await account.get();
        if (currentUser.email.toLowerCase() === email.toLowerCase()) {
          this.markEmailAsRegistered(email);
          return { exists: true, isNewUser: false };
        }
      } catch {
        // Not logged in, continue
      }
      
      // Return true to allow OTP flow
      return { exists: true, isNewUser: undefined };
    } catch (error) {
      console.error('Check user exists failed:', error);
      return { exists: true, error };
    }
  }

  // ========== Email/Password Authentication ==========

  /**
   * Register with email and password
   * Creates a new account and sends email verification
   */
  async registerWithEmailPassword(email: string, password: string, name?: string) {
    try {
      console.log('[registerWithEmailPassword] Starting registration for:', email);
      
      // Check if already logged in - if so, logout first
      try {
        await account.get();
        console.log('[registerWithEmailPassword] User already logged in, logging out first');
        await account.deleteSession('current');
      } catch {
        // Not logged in, continue with registration
      }

      // Create new account with email and password
      const user = await account.create(
        ID.unique(),
        email,
        password,
        name
      );
      
      console.log('[registerWithEmailPassword] Account created successfully:', user.$id);

      // Create email/password session for the new user
      await account.createEmailPasswordSession(email, password);
      
      console.log('[registerWithEmailPassword] Session created, sending verification email');

      // Send email verification
      const verification = await account.createVerification(
        `${window.location.origin}/verify-email`
      );
      
      console.log('[registerWithEmailPassword] Verification email sent');
      
      return { 
        success: true, 
        user,
        verification,
        message: 'Registration successful! Please check your email to verify your account.'
      };
    } catch (error: any) {
      console.error('[registerWithEmailPassword] Registration failed:', error);
      
      // Handle specific error cases
      if (error.code === 409) {
        return { 
          success: false, 
          error: { 
            message: 'An account with this email already exists. Please login instead.', 
            code: 409 
          }
        };
      }
      
      return { success: false, error };
    }
  }

  /**
   * Login with email and password
   * Returns session if successful, or indicates if 2FA is required
   */
  async loginWithEmailPassword(email: string, password: string) {
    try {
      console.log('[loginWithEmailPassword] Starting login for:', email);
      
      // Check if already logged in - if so, logout first
      try {
        const currentUser = await account.get();
        console.log('[loginWithEmailPassword] Current user found:', currentUser.email);
        
        if (currentUser.email.toLowerCase() === email.toLowerCase()) {
          console.log('[loginWithEmailPassword] Already logged in with same email');
          return { 
            success: true,
            alreadyLoggedIn: true,
            user: currentUser
          };
        }
        
        // Logged in with different email - logout first
        console.log('[loginWithEmailPassword] Logging out current user');
        await account.deleteSession('current');
      } catch {
        // Not logged in, continue
      }

      // Create email/password session
      const session = await account.createEmailPasswordSession(email, password);
      
      console.log('[loginWithEmailPassword] Session created successfully');

      // Get user details to check if 2FA is enabled
      const user = await account.get();
      
      // Check if user has 2FA enabled
      const mfaFactors = await account.listMfaFactors();
      const has2FA = mfaFactors.totp || mfaFactors.phone || mfaFactors.email;
      
      if (has2FA) {
        console.log('[loginWithEmailPassword] 2FA is enabled for this user');
        return {
          success: true,
          requires2FA: true,
          user,
          session
        };
      }
      
      console.log('[loginWithEmailPassword] Login successful');
      return { 
        success: true,
        user,
        session
      };
    } catch (error: any) {
      console.error('[loginWithEmailPassword] Login failed:', error);
      
      // Handle specific error cases
      if (error.code === 401) {
        return { 
          success: false, 
          error: { 
            message: 'Invalid email or password. Please try again.', 
            code: 401 
          }
        };
      }
      
      return { success: false, error };
    }
  }

  /**
   * Verify email with the token from verification email
   */
  async verifyEmail(userId: string, secret: string) {
    try {
      console.log('[verifyEmail] Verifying email for user:', userId);
      
      const result = await account.updateVerification(userId, secret);
      
      console.log('[verifyEmail] Email verified successfully');
      return { success: true, result };
    } catch (error: any) {
      console.error('[verifyEmail] Email verification failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Resend verification email
   */
  async resendVerificationEmail() {
    try {
      console.log('[resendVerificationEmail] Resending verification email');
      
      const verification = await account.createVerification(
        `${window.location.origin}/verify-email`
      );
      
      console.log('[resendVerificationEmail] Verification email sent');
      return { success: true, verification };
    } catch (error: any) {
      console.error('[resendVerificationEmail] Failed to resend verification email:', error);
      return { success: false, error };
    }
  }

  // ========== Two-Factor Authentication (2FA) ==========

  /**
   * Enable TOTP-based 2FA
   * Returns QR code URI for authenticator apps
   */
  async enable2FA() {
    try {
      console.log('[enable2FA] Enabling 2FA');
      
      // Create MFA authenticator for TOTP
      const mfaType = await account.createMfaAuthenticator(AuthenticatorType.Totp);
      
      console.log('[enable2FA] MFA authenticator created, returning secret');
      
      return{
        success: true,
        secret: mfaType.secret,
        uri: mfaType.uri // QR code URI for authenticator apps
      };
    } catch (error: any) {
      console.error('[enable2FA] Failed to enable 2FA:', error);
      return { success: false, error };
    }
  }

  /**
   * Complete 2FA setup by verifying the TOTP code
   */
  async verify2FASetup(otp: string) {
    try {
      console.log('[verify2FASetup] Verifying 2FA setup with OTP');
      
      // Verify MFA authenticator with the OTP code to complete setup
      const result = await account.updateMfaAuthenticator(AuthenticatorType.Totp, otp);
      
      console.log('[verify2FASetup] 2FA setup completed successfully');
      return { success: true, result };
    } catch (error: any) {
      console.error('[verify2FASetup] 2FA setup verification failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Disable 2FA (no OTP needed - Appwrite API doesn't require it)
   */
  async disable2FA() {
    try {
      console.log('[disable2FA] Disabling 2FA');
      
      // Delete MFA authenticator (doesn't need OTP)
      await account.deleteMfaAuthenticator(AuthenticatorType.Totp);
      
      console.log('[disable2FA] 2FA disabled successfully');
      return { success: true };
    } catch (error: any) {
      console.error('[disable2FA] Failed to disable 2FA:', error);
      return { success: false, error };
    }
  }

  /**
   * Create 2FA challenge during login
   */
  async create2FAChallenge() {
    try {
      console.log('[create2FAChallenge] Creating 2FA challenge');
      
      const challenge = await account.createMfaChallenge(AuthenticationFactor.Totp);
      
      console.log('[create2FAChallenge] Challenge created');
      return { success: true, challenge };
    } catch (error: any) {
      console.error('[create2FAChallenge] Failed to create challenge:', error);
      return { success: false, error };
    }
  }

  /**
   * Verify 2FA code during login
   */
  async verify2FALogin(challengeId: string, otp: string) {
    try {
      console.log('[verify2FALogin] Verifying 2FA code for login');
      
      // Complete the MFA challenge with OTP
      const result = await account.updateMfaChallenge(challengeId, otp);
      
      console.log('[verify2FALogin] 2FA verification successful');
      return { success: true, result };
    } catch (error: any) {
      console.error('[verify2FALogin] 2FA verification failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Check if user has 2FA enabled
   */
  async check2FAStatus() {
    try {
      const mfaFactors = await account.listMfaFactors();
      
      return {
        success: true,
        enabled: !!mfaFactors.totp,
        factors: mfaFactors
      };
    } catch (error: any) {
      console.error('[check2FAStatus] Failed to check 2FA status:', error);
      return { success: false, error };
    }
  }

  // ========== Legacy OTP Authentication (Deprecated) ==========
  // Keeping for backward compatibility, but should migrate to email/password

  /**
   * @deprecated Use registerWithEmailPassword instead
   * Login with email - send OTP for existing users only
   * Note: This method has limitations and should be replaced with email/password auth
   */
  async loginWithEmail(email: string) {
    try {
      console.log('[loginWithEmail] Starting login for:', email);
      
      // Check if user exists (currently always returns true for unified flow)
      const checkResult = await this.checkUserExists(email);
      
      if (!checkResult.exists) {
        console.log('[loginWithEmail] User does not exist');
        return { 
          success: false, 
          userExists: false,
          error: { message: 'User does not exist. Please register first.', code: 404 }
        };
      }

      // Check if already logged in
      try {
        const currentUser = await account.get();
        console.log('Current user found:', currentUser.email);
        
        if (currentUser.email.toLowerCase() === email.toLowerCase()) {
          console.log('Already logged in with same email, redirecting...');
          return { 
            success: false, 
            userExists: true, 
            alreadyLoggedIn: true,
            error: { message: 'Already logged in with this account', code: 409 }
          };
        }
        
        // Logged in with different email - logout first, then send OTP
        console.log('Logged in with different email, logging out first...');
        await account.deleteSession({ sessionId: 'current' });
      } catch (error: any) {
        // Not logged in (expected after logout), continue with login
        console.log('No active session, continuing with login');
      }

      // User exists (or we allow unified flow), create email token
      console.log('Creating email token for:', email);
      const token = await account.createEmailToken({
        userId: ID.unique(), // Will be ignored if email exists, used if creating new user
        email
      });
      
      console.log('Email token created successfully');
      console.log('Token details:', {
        userId: token.userId,
        $id: token.$id,
        expire: token.expire
      });
      
      // Mark email as registered for future reference
      this.markEmailAsRegistered(email);
      
      return { success: true, userExists: true, token };
    } catch (error: any) {
      console.error('Login with email failed:', error);
      console.error('Error details:', {
        message: error.message,
        code: error.code,
        type: error.type,
        response: error.response
      });
      return { success: false, userExists: false, error };
    }
  }

  /**
   * Register with email (send OTP for registration)
   * This is used for new user registration
   */
  async registerWithEmail(email: string) {
    try {
      // Check if already logged in - if so, logout first
      try {
        await account.get();
        // User is logged in, logout first to allow registration of new account
        await account.deleteSession({ sessionId: 'current' });
      } catch {
        // Not logged in, continue with registration
      }

      // For registration, we allow creating new users
      const token = await account.createEmailToken({
        userId: ID.unique(),
        email
      });
      
      // Mark this email as registered for future login checks
      this.markEmailAsRegistered(email);
      
      return { success: true, token };
    } catch (error) {
      console.error('Register with email failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Create email token (send OTP to email)
   * Generic method - use registerWithEmail() or loginWithEmail() for specific flows
   */
  async createEmailToken(email: string) {
    try {
      const token = await account.createEmailToken({
        userId: ID.unique(),
        email
      });
      return { success: true, token };
    } catch (error) {
      console.error('Create email token failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Create session from email token (verify OTP)
   * After successful verification, also mark email as registered
   */
  async verifyEmailToken(userId: string, secret: string) {
    try {
      console.log('Verifying email token...');
      console.log('userId:', userId);
      console.log('secret length:', secret?.length);
      
      // Check if already logged in - if so, logout first to prevent session conflict
      try {
        await account.get();
        console.log('Found existing session, deleting...');
        // User is logged in, logout first
        await account.deleteSession({ sessionId: 'current' });
        console.log('Existing session deleted');
      } catch {
        // Not logged in, continue with verification
        console.log('No existing session, continuing with verification');
      }

      console.log('Creating session with userId:', userId, 'secret:', secret);
      const session = await account.createSession({
        userId,
        secret
      });
      
      console.log('Session created successfully:', session.$id);
      
      // After successful login, get user info and mark as registered
      try {
        const user = await account.get();
        this.markEmailAsRegistered(user.email);
      } catch (error) {
        console.error('Failed to mark email as registered after login:', error);
      }
      
      return { success: true, session };
    } catch (error) {
      console.error('Verify email token failed:', error);
      return { success: false, error };
    }
  }

  // ========== Legacy Password Authentication (Kept for backward compatibility) ==========

  /**
   * Login with email and password (Legacy method)
   */
  async emailLogin(email: string, password: string) {
    try {
      const session = await account.createEmailPasswordSession({
        email,
        password
      });
      return { success: true, session };
    } catch (error) {
      console.error('Email login failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Register with email and password (Legacy method)
   */
  async emailRegister(email: string, password: string, name: string) {
    try {
      const user = await account.create({
        userId: ID.unique(),
        email,
        password,
        name
      });
      // Auto login after registration
      const session = await account.createEmailPasswordSession({
        email,
        password
      });
      return { success: true, user, session };
    } catch (error) {
      console.error('Email registration failed:', error);
      return { success: false, error };
    }
  }

  /**
   * OAuth login with Google or GitHub
   */
  async oauthLogin(provider: OAuthProvider) {
    try {
      const redirectUrl = `${window.location.origin}/auth/callback`;
      const fallbackUrl = `${window.location.origin}/login`;
      
      // Map our provider to Appwrite's OAuthProvider
      const appwriteProvider = provider === 'google' 
        ? 'google' as AppwriteOAuthProvider
        : 'github' as AppwriteOAuthProvider;
      
      account.createOAuth2Session({
        provider: appwriteProvider,
        success: redirectUrl,
        failure: fallbackUrl
      });
      
      return { success: true };
    } catch (error) {
      console.error('OAuth login failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Get current user
   */
  async getCurrentUser() {
    try {
      const user = await account.get();
      return { success: true, user };
    } catch (error) {
      return { success: false, error };
    }
  }

  /**
   * Logout (delete current session)
   */
  async logout() {
    try {
      console.log('Logging out - deleting current session...');
      await account.deleteSession({
        sessionId: 'current'
      });
      console.log('Session deleted successfully');
      return { success: true };
    } catch (error: any) {
      console.error('Logout failed:', error);
      console.error('Logout error details:', {
        message: error.message,
        code: error.code,
        type: error.type
      });
      return { success: false, error };
    }
  }

  /**
   * Logout from all devices (delete all sessions)
   */
  async logoutAll() {
    try {
      await account.deleteSessions();
      return { success: true };
    } catch (error) {
      console.error('Logout all failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Check if user is authenticated
   */
  async isAuthenticated() {
    const result = await this.getCurrentUser();
    return result.success;
  }

  // ========== Password Recovery ==========

  /**
   * Send password recovery email
   */
  async sendPasswordRecovery(email: string, resetUrl?: string) {
    try {
      const url = resetUrl || `${window.location.origin}/reset-password`;
      await account.createRecovery({
        email,
        url
      });
      return { success: true };
    } catch (error) {
      console.error('Send password recovery failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Complete password recovery with new password
   */
  async confirmPasswordRecovery(userId: string, secret: string, password: string) {
    try {
      await account.updateRecovery({
        userId,
        secret,
        password
      });
      return { success: true };
    } catch (error) {
      console.error('Confirm password recovery failed:', error);
      return { success: false, error };
    }
  }

  // ========== Email Verification ==========

  /**
   * Send email verification
   */
  async sendEmailVerification(verificationUrl?: string) {
    try {
      const url = verificationUrl || `${window.location.origin}/verify-email`;
      await account.createVerification({
        url
      });
      return { success: true };
    } catch (error) {
      console.error('Send email verification failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Confirm email verification
   */
  async confirmEmailVerification(userId: string, secret: string) {
    try {
      await account.updateVerification({
        userId,
        secret
      });
      return { success: true };
    } catch (error) {
      console.error('Confirm email verification failed:', error);
      return { success: false, error };
    }
  }

  // ========== MFA (Multi-Factor Authentication) ==========

  /**
   * Create TOTP authenticator for MFA
   */
  async createMFAAuthenticator() {
    try {
      const result = await account.createMFAAuthenticator('totp' as any);
      return { success: true, data: result };
    } catch (error) {
      console.error('Create MFA authenticator failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Verify TOTP authenticator with OTP code
   */
  async verifyMFAAuthenticator(otp: string) {
    try {
      const result = await account.updateMFAAuthenticator('totp' as any, otp);
      return { success: true, data: result };
    } catch (error) {
      console.error('Verify MFA authenticator failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Create MFA challenge (request OTP during login)
   */
  async createMFAChallenge(factor: 'totp' | 'email' | 'phone' = 'totp') {
    try {
      const result = await account.createMFAChallenge(factor as any);
      return { success: true, challenge: result };
    } catch (error) {
      console.error('Create MFA challenge failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Complete MFA challenge with OTP
   */
  async completeMFAChallenge(challengeId: string, otp: string) {
    try {
      const result = await account.updateMFAChallenge({
        challengeId,
        otp
      });
      return { success: true, data: result };
    } catch (error) {
      console.error('Complete MFA challenge failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Enable or disable MFA
   */
  async updateMFAStatus(enabled: boolean) {
    try {
      await account.updateMFA({
        mfa: enabled
      });
      return { success: true };
    } catch (error) {
      console.error('Update MFA status failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Get MFA factors
   */
  async getMFAFactors() {
    try {
      const factors = await account.listMFAFactors();
      return { success: true, factors };
    } catch (error) {
      console.error('Get MFA factors failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Generate MFA recovery codes
   */
  async generateMFARecoveryCodes() {
    try {
      const result = await account.createMFARecoveryCodes();
      return { success: true, recoveryCodes: result };
    } catch (error) {
      console.error('Generate MFA recovery codes failed:', error);
      return { success: false, error };
    }
  }

  // ========== Session Management ==========

  /**
   * List all active sessions
   */
  async listSessions() {
    try {
      const sessions = await account.listSessions();
      return { success: true, sessions };
    } catch (error) {
      console.error('List sessions failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Get a specific session
   */
  async getSession(sessionId: string = 'current') {
    try {
      const session = await account.getSession({
        sessionId
      });
      return { success: true, session };
    } catch (error) {
      console.error('Get session failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Update session (extend session)
   */
  async updateSession(sessionId: string = 'current') {
    try {
      const session = await account.updateSession({
        sessionId
      });
      return { success: true, session };
    } catch (error) {
      console.error('Update session failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Delete a specific session (logout from specific device)
   */
  async deleteSession(sessionId: string) {
    try {
      await account.deleteSession({
        sessionId
      });
      return { success: true };
    } catch (error) {
      console.error('Delete session failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Check if session is about to expire
   */
  async checkSessionExpiry(sessionId: string = 'current') {
    try {
      const result = await this.getSession(sessionId);
      if (result.success && result.session) {
        const session = result.session as Models.Session;
        const expiryTime = new Date(session.expire).getTime();
        const currentTime = Date.now();
        const timeUntilExpiry = expiryTime - currentTime;
        
        // Return true if session expires in less than 5 minutes
        return {
          success: true,
          isExpiring: timeUntilExpiry < 5 * 60 * 1000,
          timeUntilExpiry,
          expiryDate: new Date(session.expire)
        };
      }
      return { success: false, isExpiring: true };
    } catch (error) {
      console.error('Check session expiry failed:', error);
      return { success: false, isExpiring: true };
    }
  }

  // ========== Account Linking (Identity Management) ==========

  /**
   * List linked identities (OAuth providers)
   */
  async listIdentities() {
    try {
      const identities = await account.listIdentities();
      return { success: true, identities };
    } catch (error) {
      console.error('List identities failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Delete an identity (unlink OAuth provider)
   */
  async deleteIdentity(identityId: string) {
    try {
      await account.deleteIdentity({
        identityId
      });
      return { success: true };
    } catch (error) {
      console.error('Delete identity failed:', error);
      return { success: false, error };
    }
  }

  // ========== User Profile Management ==========

  /**
   * Update user name
   */
  async updateName(name: string) {
    try {
      const user = await account.updateName({
        name
      });
      return { success: true, user };
    } catch (error) {
      console.error('Update name failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Update user email
   */
  async updateEmail(email: string, password: string) {
    try {
      const user = await account.updateEmail({
        email,
        password
      });
      return { success: true, user };
    } catch (error) {
      console.error('Update email failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Update user password
   */
  async updatePassword(newPassword: string, oldPassword?: string) {
    try {
      const user = await account.updatePassword({
        password: newPassword,
        oldPassword
      });
      return { success: true, user };
    } catch (error) {
      console.error('Update password failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Get account preferences
   */
  async getPreferences() {
    try {
      const prefs = await account.getPrefs();
      return { success: true, preferences: prefs };
    } catch (error) {
      console.error('Get preferences failed:', error);
      return { success: false, error };
    }
  }

  /**
   * Update account preferences
   */
  async updatePreferences(prefs: object) {
    try {
      const preferences = await account.updatePrefs({
        prefs
      });
      return { success: true, preferences };
    } catch (error) {
      console.error('Update preferences failed:', error);
      return { success: false, error };
    }
  }

  // ========== Avatar Management ==========

  /**
   * Get user avatar URL from Appwrite Avatars service
   * Uses initials-based avatar generation
   */
  getUserAvatarUrl(nameOrEmail: string, size: number = 80): string {
    try {
      // Generate initials avatar URL
      const endpoint = import.meta.env.VITE_APPWRITE_ENDPOINT;
      const projectId = import.meta.env.VITE_APPWRITE_PROJECT_ID;
      
      // URL encode the name
      const encodedName = encodeURIComponent(nameOrEmail);
      
      // Generate avatar URL with initials
      return `${endpoint}/avatars/initials?name=${encodedName}&width=${size}&height=${size}&project=${projectId}`;
    } catch (error) {
      console.error('Get avatar URL failed:', error);
      return '';
    }
  }
}

export const authService = new AuthService();
